//
//  GameScene.cpp
//  AtmKiller
//
//  Created by USoft on 6/4/14.
//
//

#include "GameScene.h"
GameScene::GameScene() {
    this->timeToShowFullScreenAds = 0;
    this->isShaked = false;
    this->isTurnOffTuto = false;
    this->createLayers();
    this->createLayersContent();
    this->initGame();
    this->scheduleUpdate();
    
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    AnalyticX::flurryStartSession("WQ5HW28MQH3QXRXGFZGX");
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    AnalyticX::flurryStartSession("N23B585764WH96FHQ3YJ");
#endif

}

GameScene::~GameScene() {
}

void GameScene::onEnter() {
    AbstractScene::onEnter();
    this->touchesRegister();
}

void GameScene::onExit() {
    AbstractScene::onExit();
    this->unscheduleUpdate();
    this->removeAllChildrenWithCleanup(true);
    //_eventDispatcher->removeEventListenersForTarget(this);
}

void GameScene::addObject(Obj* obj, int zOrder, Layer* layer) {
    for (int i = 0; i < obj->getFaces()->count(); i++) {
        //Face
        {
            Face* currentFace = dynamic_cast<Face*>(obj->getFaces()->getObjectAtIndex(i));
            if (currentFace != NULL)
            {
                currentFace->setPosition(obj->getBody()->getPosition());
                if (currentFace->getParent() == NULL) {
                    layer->addChild(currentFace, zOrder - i);
                }
            }
        }
        //FaceBone
        {
            FaceBone* currentFace = dynamic_cast<FaceBone*>(obj->getFaces()->getObjectAtIndex(i));
            if (currentFace != NULL)
            {
                if (currentFace->getParent() == NULL) {
                    layer->addChild(currentFace, zOrder);
                }
            }
            
        }
    }
}

void GameScene::createLayers() {
    GameModel* gameModel = GameModel::getInstance();
    //grayLayer
    this->grayLayer = UGLayerColor::create();
    this->grayLayer->initWithColor(Color4B(0,0,0,100));
    
    // background layer
    this->backgroundLayer = UGLayer::create();
    this->backgroundLayer->setPosition(Point::ZERO);
    
    // midground layer
    this->midgroundLayer = UGLayer::create();
    this->midgroundLayer->setPosition(gameModel->getVectorMove());
    
    // foreground layer
    this->foregroundLayer = UGLayer::create();
    this->foregroundLayer->setPosition(Point::ZERO);
    
    // game layer
    this->gameLayer = UGLayer::create();
    this->gameLayer->setPosition(gameModel->getVectorMove());
    
    //upper game layer
    this->upperGameLayer = UGLayer::create();
    this->upperGameLayer->setPosition(Point::ZERO);
    // menu layer
    this->menuLayer = MenuLayer::create();
    this->menuLayer->setPosition(Point::ZERO);
    {
        this->menuLayer->getResumeButton()->setCallback(CC_CALLBACK_1(GameScene::onButtonClick, this));
        this->menuLayer->getAchievementButton()->setCallback(CC_CALLBACK_1(GameScene::onButtonClick,this));
        this->menuLayer->getStatButton()->setCallback(CC_CALLBACK_1(GameScene::onButtonClick, this));
        this->menuLayer->getOptionButton()->setCallback(CC_CALLBACK_1(GameScene::onButtonClick, this));
        this->menuLayer->getConversionButton()->setCallback((CC_CALLBACK_1(GameScene::onButtonClick, this)));
    }
    // tutorial layer
    this->tutorialLayer = UGLayer::create();
    this->tutorialLayer->setPosition(Point::ZERO);
    // achievement layer
    this->achievementLayer = AchievementLayer::create();
    this->achievementLayer->setPosition(Point::ZERO);
    // gui layer
    this->guiLayer = GUILayer::create();
    this->guiLayer->setPosition(Point::ZERO);
    {
        this->guiLayer->getCharacterButton()->setCallback(CC_CALLBACK_1(GameScene::onButtonClick, this));
        this->guiLayer->getPauseButton()->setCallback(CC_CALLBACK_1(GameScene::onButtonClick,this));
        //        this->guiLayer->getShoppingButton()->setCallback(CC_CALLBACK_1(GameScene::onButtonClick,this));
    }
    
    //upgrade layer
    this->upgradeLayer = UpgradeLayer::create();
    this->upgradeLayer->setPosition(Point::ZERO);
    
    //option layer
    this->optionLayer = OptionLayer::create();
    this->optionLayer->setPosition(Point::ZERO);
    //statistics layer
    this->statsLayer = StatisticsLayer::create();
    this->statsLayer->setPosition(Point::ZERO);
    
    //conversion layer
    this->conversionLayer = ConversionLayer::create();
    this->conversionLayer->setPosition(Point::ZERO);
    
    //add layer to this scene

    this->addChild(this->backgroundLayer, 1);
    this->addChild(this->midgroundLayer, 2);
    this->addChild(this->foregroundLayer, 3);
    this->addChild(this->gameLayer, 4);
    this->addChild(this->upperGameLayer,5);
    this->addChild(this->guiLayer,6);
    this->addChild(this->upgradeLayer,7);
    this->addChild(this->menuLayer,8);
    this->addChild(this->achievementLayer,9);
    this->addChild(this->optionLayer,10);
    this->addChild(this->statsLayer, 11);
    this->addChild(this->conversionLayer,12);
    this->addChild(this->grayLayer, 13);
    this->addChild(this->tutorialLayer,14);
}

void GameScene::createLayersContent() {
    GameModel* gameModel = GameModel::getInstance();
    Size gameSize = gameModel->getDisplayResolutionSize();
    
    // forebackground layer
    Face* foreground = new Face();
    foreground->initWithFile(BG_FORE);
    foreground->setPosition(Point(gameSize.width / 2, gameSize.height /2));
    
    Face* background = new Face();
    background->initWithFile(BG_BACK);
    background->setPosition(Point(gameSize.width / 2, gameSize.height / 2));
    
    this->backgroundLayer->addChild(background);
    this->foregroundLayer->addChild(foreground);
    // tutorial layer
    Face* tutoFace = new Face();
    tutoFace->initWithFile(BG_TUTO);
    tutoFace->setPosition(gameSize.width / 2, gameSize.height /2);
    this->tutorialLayer->addChild(tutoFace);
    // game layer
    Atm* atm = gameModel->getAtm();
    AtmInformation* atmInfo = gameModel->getAtmInformation();
    AtmBonus* atmBonus = (AtmBonus*)atmInfo->getBonusInfo()->getObjectAtIndex(atm->getBonusLevel());
    this->atmFace = new Face();
    this->atmFace->initWithSpriteFrameName(atmBonus->getBonusFace());
    this->atmFace->setAnchorPoint(Point(0.5,0));
    this->atmFace->setPosition(ATM_X, 20);
    this->gameLayer->addChild(this->atmFace);
    
    // add char
    this->addCharacter();
}

void GameScene::addCharacter() {
    GameModel* gameModel = GameModel::getInstance();
    __Array* allKeys = gameModel->getCharacters()->allKeys();
    if (allKeys != NULL) {
        for (int i = 0; i < allKeys->count(); i++) {
            __Integer* key = (__Integer*) allKeys->getObjectAtIndex(i);
            Character* character = (Character*) gameModel->getCharacters()->objectForKey(key->getValue());
            if (character != NULL) {
                if (character->getCharacterId() == CHAR_GOD) {
                    this->addObject(character, INDEX_CHARACTER, this->midgroundLayer);
                }
                else if(character->getCharacterId() == CHAR_GAME_DEV) {
                    this->addObject(character, INDEX_GAME_DEV, this->upperGameLayer);
                }
                else if(character->getCharacterId() == CHAR_GRANDMA) {
                    this->addObject(character, INDEX_GRANDMA, this->gameLayer);
                }
                else {
                    this->addObject(character, INDEX_CHARACTER, this->gameLayer);
                }
                
            }
        }
    }
}

void GameScene::touchesRegister() {
    auto listener = EventListenerTouchAllAtOnce::create();
    listener->onTouchesBegan = CC_CALLBACK_2(GameScene::onTouchesBegan, this);
    listener->onTouchesEnded = CC_CALLBACK_2(GameScene::onTouchesEnded, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, atmFace);
}

void GameScene::onTouchesBegan(const std::vector<Touch*>& touches, Event* event) {
    GameModel* gameModel = GameModel::getInstance();
    for (auto touch : touches) {
        Point point = this->convertTouchToNodeSpace(touch);
        point = point - gameModel->getVectorMove();
        if(this->isTurnOffTuto == false) {
            this->isTurnOffTuto = true;
        }
        // check atm
        {
            if (gameModel->isAtmTouchable()) {
                RectBody* tempBody = new RectBody(this->atmFace->getContentSize().width, this->atmFace->getContentSize().height + 150);
                tempBody->setPosition(Point(this->atmFace->getPositionX(), this->atmFace->getPositionY()));
                
                if (Utils::checkPointInRect(tempBody, point)) {
                    __Dictionary* dict = __Dictionary::create();
                    gameModel->getSoundModel()->playEffect(EF_TOUCH, false, 0.0f);
                    this->atmFace->setScale(0.95f);
                    this->notify(REQ_COIN_APPEAR, EVT_DEFAULT, NULL, 0, NULL);
                    this->notify(REQ_EFFECT_APPEAR, NULL, NULL, 0, &point);
                }
            }
        }
    }
}

void GameScene::onTouchesEnded(const std::vector<Touch*>& touches, Event* event)
{
    this->atmFace->setScale(1.0f);
}

void GameScene::initGame() {
    GameModel* gameModel = GameModel::getInstance();
    
    GameListener* gameListener = GameListener::create();
    this->gameListener = gameListener;
    this->gameListener->setHandlerObj(this);
    this->gameListener->setCoinAppear(ug_listener_func(GameScene::onCoinAppear));
    this->gameListener->setCoinOut(ug_listener_func(GameScene::onCoinOut));
    this->gameListener->setUpgradeAtmFace(ug_listener_func(GameScene::onUpgradeAtmFace));
    this->gameListener->setEffectAppear(ug_listener_func(GameScene::onEffectAppear));
    gameModel->addListener(gameListener);
}

void GameScene::update(float dt) {
    GameModel* gameModel = GameModel::getInstance();
    gameModel->update(dt);
    this->guiLayer->update(dt);
    this->menuLayer->update(dt);
    this->achievementLayer->update(dt);
    this->upgradeLayer->update(dt);
    this->optionLayer->update(dt);
    this->statsLayer->update(dt);
    this->conversionLayer->update(dt);
    //update tuto
    if(gameModel->isPlayGame == false && this->isTurnOffTuto == false) {
        this->grayLayer->setVisible(true);
        this->tutorialLayer->setVisible(true);
    } else {
        this->grayLayer->setVisible(false);
        this->tutorialLayer->setVisible(false);
    }
    //update character and status
    __Array* allKeys = gameModel->getCharacters()->allKeys();
    if (allKeys!=NULL) {
        for(int i=0; i < allKeys->count();i++){
            __Integer* key = (__Integer*) allKeys->getObjectAtIndex(i);
            Character* character = (Character*) gameModel->getCharacters()->objectForKey(key->getValue());
            if (gameModel->getGameState() == GS_PLAY || gameModel->getGameState()== GS_CHARACTER) {
                if(character->getLevel()>0) {
                    this->fadeObject(255, character);
                } else {
                    this->fadeObject(0, character);
                }
            }
        }
    }
}

void GameScene::onCoinAppear(Ref* data) {
    __Dictionary* dict = (__Dictionary*)data;
    Coin* coin = (Coin*) dict->objectForKey("coin");
    BigNumber* flyPoint = (BigNumber*) dict->objectForKey("amount");
    __Integer* id = (__Integer*) dict->objectForKey("id");
    //add coin into gameLayer
    this->addObject(coin, INDEX_COIN, this->gameLayer);
    //produce number
    this->processPointFly(flyPoint, id->getValue());
}

void GameScene::onEffectAppear(Ref* data) {
    __Dictionary* dict = (__Dictionary*)data;
    FingerEffect* effect = (FingerEffect*)dict->objectForKey("effect");
    Face* mainFace = effect->getFace((char*)FACE_MAIN);
    this->addObject(effect, INDEX_EFFECT, this->gameLayer);
    
    //callback
    auto delayAction = DelayTime::create(0.3f);
    auto callDelAction = CallFuncN::create(CC_CALLBACK_1(GameScene::callbackDelEffect, this));
    auto sequenceAction = Sequence::create(delayAction, callDelAction, NULL);
    mainFace->runAction(sequenceAction);
}
void GameScene::callbackDelEffect(Ref* data) {
    Face* face = (Face*) data;
    face->removeFromParentAndCleanup(true);
}
void GameScene::onCoinOut(Ref* data) {
    __Dictionary* dict = (__Dictionary*)data;
    Coin* coin = (Coin*) dict->objectForKey("coin");
    this->removeObject(coin);
}

void GameScene::onUpgradeAtmFace(Ref* data) {
    //update atm
    GameModel* gameModel = GameModel::getInstance();
    Atm* atm = gameModel->getAtm();
    AtmInformation* atmInfo = gameModel->getAtmInformation();
    AtmBonus* atmBonus = (AtmBonus*)atmInfo->getBonusInfo()->getObjectAtIndex(atm->getBonusLevel());
    this->atmFace->setSpriteFrame(atmBonus->getBonusFace());
}

void GameScene::removeObject(Obj *obj) {
    for (int i = 0; i < obj->getFaces()->count(); i++) {
        Face* face = (Face*) obj->getFaces()->getObjectAtIndex(i);
        face->removeFromParentAndCleanup(true);
    }
}

void GameScene::fadeObject(int fade, Obj* obj) {
    if (obj == NULL) {
        return;
    }
    for (int i = 0; i < obj->getFaces()->count(); i++) {
        Face* currentFace = (Face*)obj->getFaces()->getObjectAtIndex(i);
        currentFace->setPosition(obj->getBody()->getPosition());
        currentFace->setOpacity(fade);
    }
}

void GameScene::onButtonClick(Ref* sender) {
    GameModel* gameModel = GameModel::getInstance();
    //GUI Layer
    {
        if (sender == this->guiLayer->getCharacterButton()) {
            AnalyticX::flurryLogEvent("Show Upgrade Table");
            this->timeToShowFullScreenAds++;
            this->notify(REQ_UPGRADE, EVT_CLICK_BUTTON, NULL, 0, NULL);
        } else if (sender == this->guiLayer->getPauseButton()) {
            if(gameModel->getGameState() == GS_PLAY) {
                this->timeToShowFullScreenAds++;
                this->notify(REQ_PAUSE, EVT_CLICK_BUTTON,NULL,0,NULL);
            }
        }
        if (this->timeToShowFullScreenAds >= 5) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
            this->timeToShowFullScreenAds = 0;
            AppUtils::showAdFullscreen();
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
            this->timeToShowFullScreenAds = 0;
            Application* application = Application::getInstance();
            application->openURL(":setFullAdVisible:");
#endif
        }
        
    }
    //Menu Layer
    {
        if(sender == this->menuLayer->getResumeButton()) {
            this->notify(REQ_RESUME, EVT_CLICK_BUTTON, NULL, 0, NULL);
        }
        if(sender == this->menuLayer->getAchievementButton()) {
            AnalyticX::flurryLogEvent("Show Achievement Table");
            this->notify(REQ_ACHIEVEMENT, EVT_CLICK_BUTTON, NULL, 0, NULL);
        }
        if(sender == this->menuLayer->getStatButton()) {
            AnalyticX::flurryLogEvent("Show Statistics Table");
            this->notify(REQ_STATS, EVT_CLICK_BUTTON, NULL, 0, NULL);
        }
        if(sender == this->menuLayer->getConversionButton()) {
            this->notify(REQ_CONVERSION, EVT_CLICK_BUTTON, NULL, 0, NULL);
        }
        if(sender == this->menuLayer->getOptionButton()) {
            this->notify(REQ_OPTION, EVT_CLICK_BUTTON, NULL, 0, NULL);
        }
    }
}

void GameScene::processPointFly(BigNumber* amount, int coinFrom){
    //create pointText face
    char amountText[100];
    char* amountTextTemp = amount->display();
    sprintf(amountText, "+%s", amountTextTemp);
    Label* pointLabel = Utils::createLabel(amountText, (char*)FONT_TRANSFORMER, 40);
    pointLabel->setDimensions(500, pointLabel->getContentSize().height);
    pointLabel->setColor(Color3B(91, 255, 0));
    pointLabel->enableOutline(Color4B(0, 0, 0,255),3);
    pointLabel->setPosition(Point(this->atmFace->getPositionX()-30,this->atmFace->getPositionY() + this->atmFace->getContentSize().height/3 - 15 + coinFrom * 25));
    FiniteTimeAction* fadeOut = FadeOut::create(1.5f);
    FiniteTimeAction* moveByAction = CCMoveBy::create(1.5f, Point(0,100));
    FiniteTimeAction* callDelFunc = __CCCallFuncO::create(this, callfuncO_selector(GameScene::delFuncCallback), pointLabel);
    FiniteTimeAction* delayAction = DelayTime::create(1.0f);
    FiniteTimeAction* sequenceAction = Sequence::create(moveByAction, delayAction, callDelFunc, NULL);
    FiniteTimeAction* sporeAction = Spawn::create(fadeOut, sequenceAction, NULL);
    pointLabel->runAction(sporeAction);
    this->gameLayer->addChild(pointLabel, INDEX_POINT_TEXT);
}

void GameScene::delFuncCallback(Ref* data)
{
    Label* label = (Label*) data;
    label->removeFromParentAndCleanup(true);
}